package com.beauty.dressing.common.video;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.databinding.DataBindingUtil;
import android.databinding.ObservableBoolean;
import android.databinding.ObservableField;
import android.databinding.ObservableInt;
import android.graphics.Bitmap;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.GestureDetector;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.RelativeLayout;
import android.widget.SeekBar;

import com.beauty.dressing.LBApplication;
import com.beauty.dressing.R;
import com.beauty.dressing.common.bean.Video;
import com.beauty.dressing.common.interfaces.IShareDialog;
import com.beauty.dressing.common.receiver.NetworkChangedReceive;
import com.beauty.dressing.common.utils.NetTools;
import com.beauty.dressing.common.utils.Tools;
import com.beauty.dressing.databinding.VideoplayerBinding;
import com.framework.common.base.IActivity;
import com.framework.common.utils.ILog;
import com.framework.common.utils.INetworkUtils;
import com.ksyun.media.player.IMediaPlayer;
import com.ksyun.media.player.KSYMediaPlayer;
import com.xiaolanba.commonlib.fresco.FrescoUtil;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by Bond on 2016/11/08 11:27
 * you can contact me at qbaowei@qq.com
 * <p>
 * 视频列表view，悬浮于滚动的视图之上
 */

public class VideoPlayer extends FrameLayout implements LifeCycleChangeListener, NetworkChangeListener {

    //private final String ERR_VIDEO = "[vp]Parameter video is null or url is empty.Neither video play callback nor activity callback can be null.";
    private final String ERR_PLAYING = "[vp]Video is playing.";
    private final String ERR_NOTPLAYING = "[vp]Video is not playing.";
    private final String ERR_NOTREALPLAYING = "[vp]Video is not real playing";
    private final String ERR_STOP = "[vp]Video has been stop.";
    private final String ERR_PLAYCALLBACK = "[vp]Neither video play callback nor activity callback can be null.";
    private final String ERR_PAUSE_FORMAT = "[vp]Video %d can not be paused for some reason now.";
    private final String ERR_SEEK = "[vp]Video can not be seeked for some reason now.";

    /**
     * 只显示播放view
     */
    private final int DURATION_ONLY_VIDEO = 3000;

    private ObservableBoolean mCollected = new ObservableBoolean();
    private ObservableInt mDuration = new ObservableInt();
    private ObservableInt mProgress = new ObservableInt();
    private ObservableInt mSecondProgress = new ObservableInt();
    /**
     * 1.显示缓冲的时候，会隐藏header和footer
     * 2.显示header的时候会同时显示footer
     * 3.隐藏footer的时候会同时隐藏header
     */
    private ObservableBoolean mShowCenterCache = new ObservableBoolean();
    private ObservableBoolean mShowFooter = new ObservableBoolean();
    /**
     * 播放完成和播放错误都认为是播放结束
     */
    private ObservableBoolean mPlayStop = new ObservableBoolean();
    /**
     * 是否真正的在播放（设置状态为播放，不代表已经开始播放了，会有延迟）
     */
    private ObservableBoolean mRealPlaying = new ObservableBoolean();
    /**
     * 真正start完成（就是调用start之后并且开始播放了）
     */
    private ObservableBoolean mStared = new ObservableBoolean();
    private ObservableBoolean mScreenLandscape = new ObservableBoolean();

    /**
     * 是否正在播放广告
     */
    private ObservableBoolean mAdPlaying = new ObservableBoolean();
    private boolean mAdPlayedOnce = false;
    /**
     * 声音有没有打开
     */
    private ObservableBoolean mSoundOpen = new ObservableBoolean(true);
    public VideoplayerBinding mBinding;

    private Handler mHandler = new Handler();
    private Handler mBackHandler;
    private HandlerThread mHandlerThread;

    /**
     * 竖屏的时候，全屏，但是播放器本身不全屏，横屏和其他的逻辑一样
     */
    private ObservableBoolean mSimpleMode = new ObservableBoolean();

    public enum SCENE_USED {
        /**
         * 一般的页面里面只有一个播放器
         */
        NORMAL,
        /**
         * 悬浮在列表上面
         */
        SUSPEND_ON_LIST
    }

    private ObservableField<SCENE_USED> mSceneUsed = new ObservableField<>(SCENE_USED.NORMAL);

    private VideoViewHolderListener mVideoViewHolderListener;
    private ActivityListener mActivityListener;
    private ListVideoLayoutListener mListVideoLayoutListener;

    /**
     * 停止播放之前希望的播放状态
     */
    private PLAYSTATUS mPlaystatusWhenOnPause = PLAYSTATUS.IDLE;
    /**
     * 目标播放状态
     */
    private PLAYSTATUS mPlaystatus = PLAYSTATUS.IDLE;

    /**
     * 暂停的时候播放的那一帧
     */
    private Bitmap mLastFrameBitmap;

    private enum PLAYSTATUS {
        IDLE, PLAY, PAUSE
    }

    private TIP mTip = TIP.HIDE;

    private enum TIP {
        HIDE, NOT_WIFI, PLAY_ERROR, NO_NETWORK
    }

    /**
     * 上一次检查时播放的位置
     */
    private long mPreviousPosition;


    /**
     * 从全屏恢复竖屏的时候，要恢复原来的坐标和宽高
     */
    private int mWidthOnPortrait;

    /**
     * 处理手势事件
     */
    private GestureDetector mGestureDetector;
    private GesutreListener mGesutreListener;


    private VideoPositionCacheManager mPositionCacheManager;

    private boolean isLocalUrl = false;

    public VideoPlayer(Context context) {
        super(context);
        init(context, null);
    }

    public VideoPlayer(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    public VideoPlayer(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs);
    }

    private void init(Context context, AttributeSet attrs) {
        View view = LayoutInflater.from(context).inflate(R.layout.videoplayer, this, false);
        mBinding = DataBindingUtil.bind(view);
        mBinding.setCollected(mCollected);
        mBinding.setDuration(mDuration);
        mBinding.setProgress(mProgress);
        mBinding.setSecondProgress(mSecondProgress);
        mBinding.setShowCenterCache(mShowCenterCache);
        mBinding.setShowFooter(mShowFooter);
        mBinding.setPlayStop(mPlayStop);
        mBinding.setRealPlaying(mRealPlaying);
        mBinding.setStarted(mStared);
        mBinding.setScreenLandscape(mScreenLandscape);
        mBinding.setPlayingAd(mAdPlaying);
        mBinding.setSoundOpen(mSoundOpen);
        mBinding.setFullScreenClick(mFullScreenClick);
        mBinding.setSeekBarChangeListener(mSeekBarChangeListener);
//        mBinding.setSceneUsed(mSceneUsed);
        mBinding.setSimpleMode(mSimpleMode);
        addView(mBinding.getRoot());
        setOnTouchListener(mVideoViewTouchClick);

        mBinding.videoView.setVideoScalingMode(KSYMediaPlayer.VIDEO_SCALING_MODE_SCALE_TO_FIT);
        mBinding.videoView.setOnPreparedListener(mPreparedListener);
        mBinding.videoView.setOnCompletionListener(mCompletionListener);
        mBinding.videoView.setOnErrorListener(mErrorListener);
        mBinding.videoView.setOnVideoSizeChangedListener(mVideoSizeChangedListener);
        mBinding.videoView.setScreenOnWhilePlaying(true);
        mBinding.videoView.setBufferTimeMax(1.0f);
        mBinding.videoView.setTimeout(60, 60);
        mBinding.playImg.setOnClickListener(mPlayClick);
        mBinding.replayLayout.setOnClickListener(mClickReplay);
        mBinding.tipSubtitleTxt.setOnClickListener(mTipViewClick);
        mBinding.tipSubsubtitleTxt.setOnClickListener(mClickTipViewStopPlay);
        mBinding.backImg.setOnClickListener(mBackClick);
        mBinding.collectImg.setOnClickListener(mCollectClick);
        mBinding.shareImg.setOnClickListener(mShareClick);
        mBinding.adSoundMutedBtn.setOnClickListener(mSoundOpenClick);
        mBinding.adSkipTxt.setOnClickListener(mSkipAdClick);
        mBinding.adDetailTxt.setOnClickListener(mDetailClick);

        mPositionCacheManager = VideoPositionCacheManager.getInstance();
    }

    private Handler getBackHandler(){
        if (mBackHandler == null) {
            mHandlerThread = new HandlerThread("VideoPlayer");
            mHandlerThread.start();
            mBackHandler = new Handler(mHandlerThread.getLooper());
        }
        return mBackHandler;
    }

    public boolean init(@NonNull VideoViewHolderListener videoViewHolderListener, @NonNull ActivityListener activityListener, @Nullable ListVideoLayoutListener listVideoLayoutListener, boolean simpleMode) {
        mSimpleMode.set(simpleMode);
        return init(videoViewHolderListener, activityListener, listVideoLayoutListener);
    }

    public boolean init(@NonNull VideoViewHolderListener videoViewHolderListener, @NonNull ActivityListener activityListener, @Nullable ListVideoLayoutListener listVideoLayoutListener) {
        ILog.ld("[vp]here");

        stop();
        mVideoViewHolderListener = videoViewHolderListener;
        mActivityListener = activityListener;
        mListVideoLayoutListener = listVideoLayoutListener;

        mGestureDetector = new GestureDetector(activityListener.getActivity(), mGesutreListener = new GesutreListener(activityListener.getActivity()));

        mSceneUsed.set(null == mListVideoLayoutListener ? SCENE_USED.NORMAL : SCENE_USED.SUSPEND_ON_LIST);
        if (SCENE_USED.NORMAL == mSceneUsed.get()) {//一般使用场景，touch事件由页面(Activity或者Fragment)的rootview监听
            setOnTouchListener(null);
        }

        onConfigurationChanged(null);
        if (!checkInitParameterValidAndTip()) {
            return false;
        }

        Video video = mVideoViewHolderListener.getVideo();
        ILog.li("[vp]%s in scene mode %s", video.title, mSceneUsed.get().toString());

        mBinding.titleTxt.setText(video.title);
        mCollected.set(false); //TODO 是否收藏CollectManager.getInstance().checkCollect(Constants.COLLECT_VIDEO,video.id)

        if (video != null){
            isLocalUrl = isLocalUrl(video.videoUrl);
        }
        return true;
    }

    public boolean play() {
        ILog.ld("[vp]here");
        if (!checkInitParameterValidAndTip()) {
            return false;
        } else if (isVideoPlay()) {
            return pause();
        }
        mShowCenterCache.set(true);

        if (!checkNetworkMeetAndTip()) {
            return false;
        }

        return isVideoPaused() ? resume() : start();
    }

    private boolean start() {
        ILog.ld("[vp]here");
        if (!checkInitParameterValidAndTip()) {
            return false;
        } else if (isVideoPlay()) {
            ILog.lw(ERR_PLAYING);
            return false;
        }
        setVideoPlay();
        mHandler.post(mCheckBufferingRunn);
        mStared.set(false);
        mRealPlaying.set(false);
        mBinding.videoView.requestFocus();
        getBackHandler().post(mDnsRunn);
        checkNetWorkAndToast();
        return true;
    }

    public boolean pause() {
        ILog.ld("[vp]here");
        if (!checkInitParameterValidAndTip()) {
            return false;
        } else if (!isVideoPlay()) {
            ILog.lw(ERR_NOTPLAYING);
            return false;
        }
        boolean b = true;
        try {
            Video video = mVideoViewHolderListener.getVideo();
            ILog.lw("[vp]-----pause video %s-----", video.title);
            setVideoPaused();
            mHandler.removeCallbacks(mProgressRunn);
            mHandler.removeCallbacks(mCheckBufferingRunn);
            mHandler.removeCallbacks(mCheckRealPlayingRunn);
            if (mBinding.videoView.canPause()) {
                long lastPlayPosition = getCurrentPosition();
                mPositionCacheManager.savePosition(video.id, lastPlayPosition);
                ILog.li("[vp]Video pause position %s", formatSecond(lastPlayPosition / 1000));
                mBinding.videoView.pause();
                saveLastFrameBitmap();
                setLastFrameBitmap();
            } else {
                ILog.lw(ERR_PAUSE_FORMAT, video.id);
            }
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            ILog.le(throwable);
            b = false;
        }

        return b;
    }

    public boolean resume() {
        ILog.ld("[vp]here");
        if (!checkInitParameterValidAndTip()) {
            return false;
        } else if (isVideoPlay()) {
            ILog.lw(ERR_PLAYING);
            return false;
        }
        setVideoPlay();
        mRealPlaying.set(false);
        Video video = mVideoViewHolderListener.getVideo();
        ILog.li("[vp]-----Resume to play video %s-----", video.videoUrl);
        try{
            mBinding.videoView.start();
        }catch (Exception e){
            e.printStackTrace();
        }
        mHandler.post(mProgressRunn);
        mHandler.post(mCheckBufferingRunn);
        mHandler.post(mCheckRealPlayingRunn);
        return true;
    }

    /**
     * 函数说明
     * 1.play,resume,pause,stop放逻辑，对应的setVideoPlay,setVideoPause,setVideoStop放ui
     */

    public boolean stop() {
        return stop(false, false);
    }

    private boolean stop(boolean playComplete, boolean playError) {
        ILog.ld("[vp]here");
        if (!checkInitParameterValid()) {
            return false;
        } else if (isVideoStop()) {
            ILog.lw(ERR_STOP);
            return false;
        }
        boolean b = true;
        try {
            ILog.lw("[vp]-----stop video %s-----", mVideoViewHolderListener.getVideo().title);
            setVideoStop(playComplete, playError);
            mHandler.removeCallbacks(mProgressRunn);
            mHandler.removeCallbacks(mCheckBufferingRunn);
            mHandler.removeCallbacks(mCheckRealPlayingRunn);
            Video video = mVideoViewHolderListener.getVideo();
            long lastPlayPosition = playComplete ? 0 : getCurrentPosition();
            mPositionCacheManager.savePosition(video.id, lastPlayPosition);
            ILog.li("[vp]Video stop position %s", formatSecond(lastPlayPosition / 1000));
            mPlaystatusWhenOnPause = PLAYSTATUS.IDLE;
            mBinding.videoView.stop();
            mBinding.videoView.reset();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            ILog.le(throwable);
            b = false;
        }

        return b;
    }

    public boolean destroy() {
        ILog.ld("[vp]here");
        if (!checkInitParameterValidAndTip()) {
            return false;
        }
        stop();
        try{
            mBinding.videoView.release();
        }catch (Exception e){
            e.printStackTrace();
        }
        mHandler.removeCallbacksAndMessages(null);
        if (mBackHandler != null) {
            mBackHandler.removeCallbacksAndMessages(null);
        }
        if (mHandlerThread != null) {
            mHandlerThread.quit();
        }
        return true;
    }

    private IMediaPlayer.OnVideoSizeChangedListener mVideoSizeChangedListener = new IMediaPlayer.OnVideoSizeChangedListener() {
        @Override
        public void onVideoSizeChanged(IMediaPlayer iMediaPlayer, int i, int i1, int i2, int i3) {
            ILog.ld("new size %d,%d", iMediaPlayer.getVideoWidth(), iMediaPlayer.getVideoHeight());
            mBinding.videoView.setVideoScalingMode(KSYMediaPlayer.VIDEO_SCALING_MODE_SCALE_TO_FIT);
        }
    };

    private IMediaPlayer.OnPreparedListener mPreparedListener = new IMediaPlayer.OnPreparedListener() {
        @Override
        public void onPrepared(IMediaPlayer mp) {
            if (null == mp) {
                ILog.le("MediaPlayer is null.");
                return;
            } else if (!checkInitParameterValidAndTip()) {
                return;
            }
            Video video = mVideoViewHolderListener.getVideo();
            ILog.ld("[vp]Video %s", video.title);
            if (isVideoPlay()) {
                try{
                    mBinding.videoView.start();
                }catch (Exception e){
                    e.printStackTrace();
                }
                mHandler.post(mProgressRunn);
                mHandler.post(mCheckRealPlayingRunn);
                mp.setOnSeekCompleteListener(mSeekCompleteListener);

                if (hasAdToPlay()) {//如果产品要求记录广告的播放位置，就在这里处理
                    ILog.li("[vp]ad is playing");
                    mAdPlaying.set(true);
                } else {
                    mAdPlaying.set(false);
                    long lastPlayPosition = mPositionCacheManager.readPosition(video.id);
                    if (0 != lastPlayPosition) {
                        ILog.li("[vp]Video seek to position %s", formatSecond(lastPlayPosition / 1000));
                        mBinding.videoView.seekTo((lastPlayPosition));
                    }
                }
            } else {
                ILog.le("[vp]After prepared, find that video %d is forced to stop.", video.id);
                stop();
            }
        }
    };

    private IMediaPlayer.OnCompletionListener mCompletionListener = new IMediaPlayer.OnCompletionListener() {
        @Override
        public void onCompletion(IMediaPlayer mp) {
            ILog.ld("[vp]here");
            stop(true, false);
            boolean isAdPlaying = mAdPlaying.get();//adPlayCompletion会修改mAdPlaying的值
            ILog.ld("[vp]isAdPlaying %b", isAdPlaying);
            if (isAdPlaying) {
                adPlayCompletion();
            } else {
                mHandler.post(mOnlyVideoViewRunn);
                mBinding.replayLayout.setVisibility(View.VISIBLE);
                if (mPlayerListener != null) {
                    mPlayerListener.onCompletion(mp);
                }
            }
        }
    };

    private void adPlayCompletion() {
        ILog.ld("[vp]in");
        Video video = mVideoViewHolderListener.getVideo();
        mAdPlayedOnce = true;
        mAdPlaying.set(false);
        play();
    }

    private IMediaPlayer.OnErrorListener mErrorListener = new IMediaPlayer.OnErrorListener() {
        @Override
        public boolean onError(IMediaPlayer mp, int what, int extra) {
            ILog.le("[vp]what %d, extra %d, %s play error", what, extra, mVideoViewHolderListener.getVideo().title);
            // TODO 播放部分视频 在最后1秒时出错， 这里置为播放完成状态
            long currPosition = getCurrentPosition();
            long duration = getDuration();
            if (duration > 1000 && duration - currPosition <= 1000) {
                mCompletionListener.onCompletion(mp);
                return true;
            }

            stop(false, true);
            if (!isLocalUrl) {
                if (NetTools.isNetAvailble(getContext())) {
                    showTip(TIP.PLAY_ERROR);
                } else {
                    showTip(TIP.NO_NETWORK);
                }
            } else {
                showTip(TIP.PLAY_ERROR);
            }
            return true;
        }
    };

    private IMediaPlayer.OnSeekCompleteListener mSeekCompleteListener = new IMediaPlayer.OnSeekCompleteListener() {
        @Override
        public void onSeekComplete(IMediaPlayer mp) {
            ILog.ld("[vp]MediaPlayer here");
            mPositionCacheManager.savePosition(mVideoViewHolderListener.getVideo().id, 0);
        }
    };

    private SeekBar.OnSeekBarChangeListener mSeekBarChangeListener = new SeekBar.OnSeekBarChangeListener() {
        @Override
        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {

        }

        @Override
        public void onStartTrackingTouch(SeekBar seekBar) {
            mHandler.removeCallbacks(mProgressRunn);
            mHandler.removeCallbacks(mCheckBufferingRunn);
        }

        @Override
        public void onStopTrackingTouch(SeekBar seekBar) {
            boolean isPaused = isVideoPaused();
            if (!isVideoPlay() && !isPaused) {
                ILog.lw("[vp]Video has been finished.");
                return;
            }
            try {
                int seekPosition = seekBar.getProgress();
                long currPosition = getCurrentPosition();
                if (seekPosition != currPosition) {
                    boolean canSeek = seekPosition > currPosition && mBinding.videoView.canSeekForward() || seekPosition < currPosition && mBinding.videoView.canSeekBackward();
                    if (canSeek) {
                        mBinding.videoView.seekTo(seekPosition);
                        if (isPaused) resume();
                    } else {
                        ILog.le(ERR_SEEK);
                    }
                } else {
                    ILog.lw("[vp]seek position = curr position, %d", seekPosition);
                }
            } catch (Throwable throwable) {
                throwable.printStackTrace();
                ILog.le(throwable);
            }

            mHandler.post(mProgressRunn);
            mHandler.post(mCheckBufferingRunn);
        }
    };

    /**
     * 如果没有网络，不会立刻停止，播放完缓存之后才会去停止并且提示错误
     */
    @Override
    public void onNetworkChanged(boolean isWifiConnectedOrConnectiong, boolean isMobileConnectedOrConnectiong) {
        ILog.ld("[vp]isWifiConnectedOrConnectiong %b, isMobileConnectedOrConnectiong %b", isWifiConnectedOrConnectiong, isMobileConnectedOrConnectiong);
        if (isLocalUrl) {
            return;
        }
        if (!checkInitParameterValid()) {
            return;
        }
        if (!isWifiConnectedOrConnectiong) {
            if (isMobileConnectedOrConnectiong ) { //YaYaController.getInstance().getCacheManager().getShowHintVideoNoWifi()
                pause();
                showTip(TIP.NOT_WIFI);
            }
        }
    }

    /**
     * 点击返回
     */
    private View.OnClickListener mBackClick = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            ILog.ld("[vp]Click back in video");
            mActivityListener.onClickVideoBack();
        }
    };

    /**
     * 点击收藏
     */
    private View.OnClickListener mCollectClick = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Video video = mVideoViewHolderListener.getVideo();
            //TODO 收藏成功 mCollected.set(true); 取消收藏 mCollected.set(false);
        }
    };

    /**
     * 点击分享
     */
    private View.OnClickListener mShareClick = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Activity activity = mActivityListener.getActivity();
            if (activity instanceof IShareDialog) {
                ((IShareDialog) activity).shareVideoLandscape(mVideoViewHolderListener.getVideo());
            } else {
                ILog.le("[vp]Activity must implements IShareDialog");
            }
        }
    };

    /**
     * 点击播放
     */
    private View.OnClickListener mPlayClick = new OnClickListener() {
        @Override
        public void onClick(View v) {
            if (isVideoPlay()) {
                pause();
            } else {
                play();
            }
        }
    };

    /**
     * 点击重播
     */
    private View.OnClickListener mClickReplay = new OnClickListener() {
        @Override
        public void onClick(View v) {
            if (!Tools.checkNetWorkAndToast()) {
                return;
            }
            mVideoViewHolderListener.onClickReplayInVideoPlayer(mVideoViewHolderListener.getVideo());
            mPlayClick.onClick(v);
        }
    };

    /**
     * 点击全屏
     */
    private View.OnClickListener mFullScreenClick = new OnClickListener() {
        @Override
        public void onClick(View v) {
            ILog.ld("[vp]Click full screen");
            mActivityListener.onClickFullScreen(VideoPlayer.this);
        }
    };


    //onclick会屏蔽掉RecyclerView的滚动，改用onTouch
    private View.OnTouchListener mVideoViewTouchClick = new View.OnTouchListener() {

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            ILog.ld("[vp]video view touch, %s", Tools.strAction(event.getAction()));

            if (!checkInitParameterValidAndTip()) {
                return false;
            }

            if (mShowCenterCache.get()) {
                ILog.lw("[vp]Video is buffering, ignore this event");
                return false;
            } else if (View.VISIBLE == mBinding.tipLayout.getVisibility()) {
                ILog.lw("[vp]Video is showing some tip or error, ignore this event");
                return false;
            }

            if (SCENE_USED.NORMAL == mSceneUsed.get()) {
                if (event.getAction() == MotionEvent.ACTION_UP) {
                    mGesutreListener.onActionUp();
                }
                return mGestureDetector.onTouchEvent(event);
            } else {

                if (isPortrait()) {
                    ILog.lw("[vp]do nothing in %s when screen orentation is portrait", SCENE_USED.SUSPEND_ON_LIST);
                } else {
                    if (event.getAction() == MotionEvent.ACTION_UP) {
                        mGesutreListener.onActionUp();
                    }
                    return mGestureDetector.onTouchEvent(event);
                }

                return false;
            }
        }
    };

    public OnTouchListener getVideoViewTouchClick() {
        return mVideoViewTouchClick;
    }

    /**
     * 轻触VideoView
     */
    public void onTapVideoView() {
        mShowFooter.set(!mShowFooter.get());
        if (mShowFooter.get()) {
            mHandler.postDelayed(mOnlyVideoViewRunn, DURATION_ONLY_VIDEO);
        } else {
            mHandler.removeCallbacks(mOnlyVideoViewRunn);
        }
    }

    public boolean isPortrait() {
        return getContext().getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
    }

    public boolean isLandscape() {
        return getContext().getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE;
    }

    /**
     * 点击提示视图
     */
    private View.OnClickListener mTipViewClick = new OnClickListener() {
        @Override
        public void onClick(View v) {
            ILog.ld("[vp]Video id is %d", mVideoViewHolderListener.getVideo().id);
            if (isLocalUrl) {
                play();
                return;
            }
            switch (mTip) {
                case NOT_WIFI:
// TODO 保存用户习惯              LBApplication.getInstance().getCacheManager().setShowHintVideoNoWifi(false);
                    play();
                    break;
                case NO_NETWORK:
                    if (Tools.checkNetWorkAndToast()) {
                        play();
                    }
                    break;
                case PLAY_ERROR:
                    play();
                    break;
                default:
                    break;
            }
        }
    };

    /**
     * 点击提示view中的停止播放
     */
    private View.OnClickListener mClickTipViewStopPlay = new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            ILog.ld("[vp]click stop play.");
            mListVideoLayoutListener.getListVideoLayout().stopFollow();
        }
    };

    private void showTip(TIP tip) {
        mTip = tip;
        if (TIP.HIDE == tip) {
            mBinding.tipLayout.setVisibility(View.GONE);
            return;
        }
        mHandler.removeCallbacks(mCheckBufferingRunn);
        mHandler.removeCallbacks(mProgressRunn);
        mShowCenterCache.set(false);
        mShowFooter.set(false);
        mBinding.replayLayout.setVisibility(View.GONE);
        mBinding.tipLayout.setVisibility(View.VISIBLE);
        switch (tip) {
            case NOT_WIFI:
                mBinding.tipTitleTxt.setText(R.string.video_unwifi_state);
                mBinding.tipSubtitleTxt.setText(R.string.continue_to_play);
                break;
            case PLAY_ERROR:
                if (checkNetworkMeetAndTip()) {//参数不正确也会提示播放错误，但是此时可能需要先提示网络问题
                    mBinding.tipTitleTxt.setText(R.string.video_play_error);
                    mBinding.tipSubtitleTxt.setText(R.string.click_retry);
                }
                break;
            case NO_NETWORK:
                mBinding.tipTitleTxt.setText(R.string.net_unconnected_please_check_settings);
                mBinding.tipSubtitleTxt.setText(R.string.click_retry);
                break;
            default:
                break;
        }
    }

    @Override
    public void onResume() {
        ILog.ld("[vp]in");
        if (!checkInitParameterValid()) {
            return;
        }
        mBinding.videoView.runInForeground();
        if (PLAYSTATUS.PLAY == mPlaystatusWhenOnPause) {
            setLastFrameBitmap();
            play();
        } else {
            boolean isReplayLayoutVisible = View.VISIBLE == mBinding.replayLayout.getVisibility();
            ILog.ld("[vp]replay layout is %s visible", isReplayLayoutVisible ? "" : "not");
            if (!isReplayLayoutVisible) {
                setLastFrameBitmap();
            }
        }
    }

    @Override
    public void onPause() {
        ILog.ld("[vp]in");
        if (!checkInitParameterValid()) {
            return;
        }
        try{
            mBinding.videoView.runInBackground(true);
        }catch (Exception e){
            e.printStackTrace();
        }
        mPlaystatusWhenOnPause = mPlaystatus;
        if (isVideoPlay()) {
            pause();
        }
    }

    @Override
    public void onStop() {
        ILog.lw("[vp]in");
        if (!checkInitParameterValid()) {
            return;
        }
        if (SCENE_USED.SUSPEND_ON_LIST == mSceneUsed.get()) {
            ILog.lw("[vp]In %s mode, stop follow when onStop", mSceneUsed.get());
            mListVideoLayoutListener.getListVideoLayout().stopFollow();
        }
    }

    @Override
    public void onDestroy() {
        ILog.lw("[vp]in");
        if (!checkInitParameterValid()) {
            return;
        }
        destroy();
    }

    @Override
    protected void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        ILog.ld("[vp]in");
        mScreenLandscape.set(isLandscape());
        if (!checkInitParameterValid()) {
            ILog.lw("[vp]This video player has not been inited.");
        } else {
            Activity activity = mActivityListener.getActivity();
            if (activity instanceof IShareDialog) {
                ((IShareDialog) activity).dismissShareDialog();
            }
            ILog.lw("[vp]Video %s here", mVideoViewHolderListener.getVideo().title);
        }

        Point screenSize = new Point();
        WindowManager windowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
        Display display = windowManager.getDefaultDisplay();
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {//这个api是版本17添加的,用19做判断是因为在版本19以上(包括19)才会去隐藏虚拟按键(版本16~19无法悬浮虚拟按键所以这些版本不做处理)
            DisplayMetrics dm = getResources().getDisplayMetrics();
            screenSize.set(dm.widthPixels, dm.heightPixels);
        } else {
            display.getRealSize(screenSize);
        }

        final ViewGroup.LayoutParams playerParams = getLayoutParams();
        final ViewGroup.LayoutParams params = mBinding.rootView.getLayoutParams();
        int orientation = null == newConfig ? getResources().getConfiguration().orientation : newConfig.orientation;
        if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
            ILog.ld("[vp]orientation landscape");
            playerParams.width = screenSize.x;
            playerParams.height = screenSize.y;
            params.width = screenSize.x;
            params.height = screenSize.y;
            ILog.ld("[vp]VideoView target size %d,%d", params.width, params.height);
            final RelativeLayout.LayoutParams rl = new RelativeLayout.LayoutParams(params.width, params.height);
            rl.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);
            mBinding.videoViewLayout.postDelayed(new Runnable() {
                @Override
                public void run() {
                    mBinding.videoViewLayout.setLayoutParams(rl);
                    mBinding.rootView.setLayoutParams(params);
                    setLayoutParams(playerParams);
                    setPosLeftTop();
                }
            }, 10);
        } else {
            ILog.ld("[vp]orientation portrait");
            if (mWidthOnPortrait > 0) {
                params.width = mWidthOnPortrait;
            } else {
                View followedView = null == mVideoViewHolderListener ? null : mVideoViewHolderListener.getFollowedView();
                params.width = null != followedView ? followedView.getWidth() : screenSize.x;
                mWidthOnPortrait = params.width;
            }
            params.height = (int) (params.width * 0.5625f);
            playerParams.width = params.width;
            playerParams.height = params.height;
            ILog.ld("[vp]VideoView target size %d,%d", params.width, params.height);
            RelativeLayout.LayoutParams rl = new RelativeLayout.LayoutParams(params.width, params.height);
            rl.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);
            mBinding.videoViewLayout.setLayoutParams(rl);
            if (mSimpleMode.get()) {
                mBinding.rootView.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
                playerParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
                playerParams.height = ViewGroup.LayoutParams.MATCH_PARENT;
                setLayoutParams(playerParams);
            } else {
                mBinding.rootView.setLayoutParams(params);
                setLayoutParams(playerParams);
            }
            restorePos();
        }
    }

    /**
     * 横屏的时候坐标设置为左上角
     */
    private void setPosLeftTop() {
        if (SCENE_USED.NORMAL == mSceneUsed.get()) {
            ILog.lw("[vp]Normal scene");
            return;
        }
        getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                getViewTreeObserver().removeGlobalOnLayoutListener(this);
                setX(0);
                setY(0);
            }
        });
    }

    private void restorePos() {
        if (SCENE_USED.NORMAL == mSceneUsed.get()) {
            ILog.lw("[vp]Normal scene");
            return;
        }
        getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                getViewTreeObserver().removeGlobalOnLayoutListener(this);
                mListVideoLayoutListener.getListVideoLayout().updateVideoViewLayoutPosition();
            }
        });
    }

    /**
     * 更新进度
     */
    private Runnable mProgressRunn = new Runnable() {
        @Override
        public void run() {
            try {
                if (isVideoPlay()) {
                    long currPosition = getCurrentPosition();
                    long duration = getDuration();
                    Video video = mVideoViewHolderListener.getVideo();
                    if (duration > 0) {
                        video.setVideoHourLong(duration / 1000);//要将毫秒转换为秒
                    } else {
                        duration = (int) video.getVideoHourLong() * 1000;//同样的将秒转换为毫秒
                    }
                    long secondPosition = mBinding.videoView.getBufferPercentage() * duration / 100;
                    currPosition = currPosition > duration ? duration : currPosition;
                    mDuration.set((int) duration);
                    mProgress.set((int) currPosition);
                    mSecondProgress.set((int) secondPosition);
                    ILog.lv("[vp]ProgressRun, progress %s, secondProgress %s, duration %s", formatSecond(currPosition / 1000), formatSecond(secondPosition / 1000), formatSecond(duration / 1000));
                    mHandler.postDelayed(mProgressRunn, 1000);//更新进度的周期
                } else {
                    ILog.le(ERR_NOTPLAYING);
                }
            } catch (Throwable throwable) {
                throwable.printStackTrace();
                ILog.le(throwable);
            }
        }
    };

    /**
     * 检查是否在缓冲
     */
    private Runnable mCheckBufferingRunn = new Runnable() {
        @Override
        public void run() {
            try {
                if (!checkInitParameterValidAndTip()) {
                    return;
                }
                if (isVideoPlay()) {
                    long currPosition = getCurrentPosition();
                    ILog.lv("[vp]CheckBuffering, mPreviousPosition = %s, currPosition = %s", formatSecond(mPreviousPosition / 1000), formatSecond((int) (currPosition / 1000)));
                    boolean isRealBuffering = mPreviousPosition == currPosition;
                    boolean isBuffering = isRealBuffering || !mRealPlaying.get();
                    if (isBuffering) {
                        ILog.lw("[vp]Video is buffering");
                    }
                    if (!isLocalUrl && isRealBuffering && !INetworkUtils.getInstance().isNetworkConnectedOrConnectiong()) {
                        ILog.lw("[vp]May be video %s buffer data has been played completely.", mVideoViewHolderListener.getVideo().title);
                        stop();
                        showTip(TIP.NO_NETWORK);
                    }
                    mShowCenterCache.set(isBuffering);
                    mPreviousPosition = currPosition;
                    mHandler.postDelayed(mCheckBufferingRunn, 1000);
                } else {
                    ILog.le("%s, %s", ERR_NOTPLAYING, "stop checking buffering");
                    mShowCenterCache.set(false);
                }
            } catch (Throwable throwable) {
                throwable.printStackTrace();
                ILog.le(throwable);
            }
        }
    };

    /**
     * 是否是本地链接
     * @param videoUrl
     * @return
     */
    private boolean isLocalUrl(String videoUrl){
        if (!TextUtils.isEmpty(videoUrl) && (videoUrl.startsWith("file://") || videoUrl.startsWith("/"))) {
            return true;
        }
        return false;
    }

    /**
     * 获取dns
     */
    private Runnable mDnsRunn = new Runnable() {
        @Override
        public void run() {
            final Video video = mVideoViewHolderListener.getVideo();
            String videoUrlToPlay = video.videoUrl;
            if (hasAdToPlay()) {
                videoUrlToPlay = video.videoAd.videoUrl;
            }
            isLocalUrl = isLocalUrl(videoUrlToPlay);
            final long lastPlayPosition = mPositionCacheManager.readPosition(video.id);
            mProgress.set((int) lastPlayPosition);
            final Map<String, String> headers = new HashMap<>();
            String dnsUrl = null;
            try {
                dnsUrl = videoUrlToPlay;
            }catch (Exception e){
                e.printStackTrace();
            }
            final String newpath = dnsUrl;
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    if (isVideoPlay()) {
                        try {
                            mBinding.videoView.setDataSource(newpath);//设置播放url
                            mBinding.videoView.prepareAsync();
                            ILog.li("[vp]-----Start to play video %s, newpath[%s]-----", video.title, newpath);
                        } catch (IOException e) {
                            e.printStackTrace();
                            ILog.le(e);
                        }
                    } else {
                        ILog.le("[vp]After get dns, find that video %d is forced to stop.", video.id);
                    }
                }
            });
        }
    };

    private boolean hasAdToPlay() {
        Video video = mVideoViewHolderListener.getVideo();
        boolean b = !mAdPlayedOnce && null != video.videoAd && !TextUtils.isEmpty(video.videoAd.videoUrl);
        ILog.ld("[vp]has ad to play %b", b);
        return b;
    }

    /**
     * 检查是否已经完全开始播放了（setVideoPlay只是设置状态为’播放‘）
     * Q:为什么要在VideoView上面盖一个黑色背景的View
     * A:因为VideoView是共用的，从一个视频切到另一个视频有些时候会短暂的显示上一个视频停止时的画面，所以需要盖住
     */
    private Runnable mCheckRealPlayingRunn = new Runnable() {
        @Override
        public void run() {
            boolean isRealPlaying = mBinding.videoView.isPlaying();
            if (isRealPlaying) {
                mBinding.videoView.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        mStared.set(true);
                        mRealPlaying.set(true);
                        mPlayStop.set(false);
                    }
                }, 200);
                mShowCenterCache.set(false);
            } else {
                if (isVideoPlay()) {
                    ILog.lw(ERR_NOTREALPLAYING);
                    mHandler.postDelayed(mCheckRealPlayingRunn, 100);
                }
            }
        }
    };

    /**
     * 只显示VideoView
     */
    private Runnable mOnlyVideoViewRunn = new Runnable() {
        @Override
        public void run() {
            mShowFooter.set(false);
        }
    };

    /**
     * 不锁定屏幕方向
     */
    private Runnable mUnlockScreenOrientationRunn = new Runnable() {
        @Override
        public void run() {
            mActivityListener.getScreenOrientationImpl().unlockScreenOrientation();
        }
    };

    /**
     * @return 初始化传入的所有参数是否可用, 并提示
     */
    private boolean checkInitParameterValid() {
        //检查参数
        boolean isParamValid = false;
        if (null == mVideoViewHolderListener) {
            ILog.le("[vp]null == mVideoViewHolderListener");
        } else if (null == mVideoViewHolderListener.getVideo()) {
            ILog.le("[vp]null == mVideoViewHolderListener.getVideo()");
        } else if (TextUtils.isEmpty(mVideoViewHolderListener.getVideo().videoUrl)) {
            ILog.le("[vp]mVideoViewHolderListener.getVideo().videoUrl is empty");
        } else if (null == mActivityListener) {
            ILog.le("[vp]null == mActivityListener");
        } else if (SCENE_USED.SUSPEND_ON_LIST == mSceneUsed.get() && null == mListVideoLayoutListener) {
            ILog.le("[vp]null == mListVideoLayoutListener, in list mode");
        } else {
            isParamValid = true;
        }
        if (!isParamValid) {
            return false;
        }
        return true;
    }

    private boolean checkInitParameterValidAndTip() {
        boolean b = checkInitParameterValid();
        if (!b) {
            showTip(TIP.PLAY_ERROR);
        }
        return b;
    }

    /**
     * @return 网络是否达到要求，并提示（不是网络可用不可用问题）
     */
    private boolean checkNetworkMeetAndTip() {
        if (isLocalUrl) {
            return true;
        }
        if (!INetworkUtils.getInstance().isNetworkAvailable()) {
            showTip(TIP.NO_NETWORK);
            return false;
        } else {
            if (!INetworkUtils.getInstance().isWifiAvailable() ) {
                showTip(TIP.NOT_WIFI);// 是否每次都显示&& LBApplication.getInstance().getCacheManager().getShowHintVideoNoWifi()
                return false;
            }
        }
        return true;
    }

    private boolean isVideoPlay() {
        boolean isPlay = PLAYSTATUS.PLAY == mPlaystatus;
        ILog.lv("[vp]Video %s is %s play status", mVideoViewHolderListener.getVideo().title, isPlay ? "" : "not");
        return isPlay;
    }

    private void setVideoPlay() {
        ILog.ld("[vp]in");
        mPlaystatus = PLAYSTATUS.PLAY;
        mBinding.videoView.setKeepScreenOn(true);
        mBinding.playImg.setImageResource(R.drawable.player_stop);
        mShowFooter.set(false);
        mBinding.tipLayout.setVisibility(View.GONE);
        mShowCenterCache.set(true);
        setLastFrameBitmap();
        mBinding.posterImg.setImageBitmap(null);
        Video video = mVideoViewHolderListener.getVideo();
        if (video!=null && !TextUtils.isEmpty(video.titleImage)) {//如果播放结束后再去加载图片，会导致灰几秒钟，这里提前加载图片
            mBinding.posterImg.setVisibility(View.GONE);
            FrescoUtil.loadImage(mBinding.posterImg, video.titleImage);
        }

        mBinding.replayLayout.setVisibility(View.GONE);
        mHandler.post(mUnlockScreenOrientationRunn);
        NetworkChangedReceive.registNetworkChangeListener(mNetworkReceiver);
    }

    private boolean isVideoPaused() {
        boolean isPaused = PLAYSTATUS.PAUSE == mPlaystatus;
        ILog.ld("[vp]Video %s is %s paused status", mVideoViewHolderListener.getVideo().title, isPaused ? "" : "not");
        return isPaused;
    }

    private void setVideoPaused() {
        ILog.ld("[vp]in");
        mPlaystatus = PLAYSTATUS.PAUSE;
        mBinding.videoView.setKeepScreenOn(false);
        mBinding.playImg.setImageResource(R.drawable.player_play);
        mShowCenterCache.set(false);
        mRealPlaying.set(false);
//        NetworkChangedReceive.unregistNetworkChangeListener(mNetworkReceiver);
        mHandler.postDelayed(mOnlyVideoViewRunn, DURATION_ONLY_VIDEO);
    }

    private boolean isVideoStop() {
        boolean isStop = PLAYSTATUS.IDLE == mPlaystatus;
        return isStop;
    }

    /**
     * 更新UI（逻辑放在stop函数里面）
     */
    private void setVideoStop(boolean playComplete, boolean playError) {
        ILog.ld("[vp]in");
        mPlaystatus = PLAYSTATUS.IDLE;
        mBinding.videoView.setKeepScreenOn(false);
        NetworkChangedReceive.unregistNetworkChangeListener(mNetworkReceiver);
        mBinding.playImg.setImageResource(R.drawable.player_play);
        mShowCenterCache.set(false);
        if (!mAdPlaying.get()) {//如果当前播放的是广告，则不处理屏幕旋转问题
            if (isLandscape()) {
                mActivityListener.onClickFullScreen(VideoPlayer.this);
            } else {
                mActivityListener.getScreenOrientationImpl().lockScreenPortrait();
            }
        }
        releaseLastFrameBitmap();
        mPlayStop.set(true);//显示遮罩
        if (playComplete) {
            mProgress.set(0);
            Video video = mVideoViewHolderListener.getVideo();
            mBinding.posterImg.setVisibility(View.VISIBLE);
            if (video!=null && !TextUtils.isEmpty(video.titleImage)) {
                FrescoUtil.loadImage(mBinding.posterImg, video.titleImage);
            } else {
                mBinding.posterImg.setImageResource(R.color.black);
            }
        }
        mRealPlaying.set(false);
    }

    private void saveLastFrameBitmap() {
        ILog.ld("[vp]in");
        releaseLastFrameBitmap();
        mLastFrameBitmap = mBinding.videoView.getScreenShot();
        ILog.ld("[vp]get last video frame %s", null != mLastFrameBitmap ? "success" : "failed");
    }

    private void releaseLastFrameBitmap() {
        ILog.lw("[vp]in");
        if (null != mLastFrameBitmap && !mLastFrameBitmap.isRecycled()) {
            mBinding.lastFrameImg.setImageBitmap(null);
            mLastFrameBitmap.recycle();
            mLastFrameBitmap = null;
        }
    }

    private void setLastFrameBitmap() {
        ILog.ld("[vp]in");
        if (null != mLastFrameBitmap && !mLastFrameBitmap.isRecycled()) {
            mBinding.lastFrameImg.setImageBitmap(mLastFrameBitmap);
        } else {
            ILog.lw("[vp]No last video frame bitmap, so use black");
            mBinding.lastFrameImg.setImageResource(R.color.black);
        }
    }

    public static String formatSecond(long seconds) {
        long hh = seconds / 3600;
        long mm = seconds % 3600 / 60;
        long ss = seconds % 60;
        String strTemp;
        if (0 != hh) {
            strTemp = String.format("%02d:%02d:%02d", hh, mm, ss);
        } else {
            strTemp = String.format("%02d:%02d", mm, ss);
        }
        return strTemp;
    }

    public interface ActivityListener {
        void onClickFullScreen(VideoPlayer videoPlayer);

        Activity getActivity();

        IScreenOrientation.ScreenOrientationImpl getScreenOrientationImpl();

        void onClickVideoBack();

        void clearVideoPlayPositionCache();
    }

    public interface ListVideoLayoutListener {
        BaseListVideoLayout getListVideoLayout();
    }

    public interface VideoViewHolderListener {
        View getFollowedView();

        Video getVideo();

        int getFollowdViewAdapterPosition();

        void onClickReplayInVideoPlayer(Video video);
    }

    private class GesutreListener extends PlayerGestureListener {

        public GesutreListener(Activity activity) {
            super(activity);
        }

        @Override
        protected boolean canHandleEvent() {
            return SCENE_USED.NORMAL == mSceneUsed.get() || (SCENE_USED.SUSPEND_ON_LIST == mSceneUsed.get() && isLandscape());
        }

        @Override
        protected boolean isVideoPrepared() {
            return mBinding.videoView.isPlaying();
        }

        @Override
        protected int getVideoCurrentProgressPosition() {
            return (int) mBinding.videoView.getCurrentPosition();
        }

        @Override
        protected void hideBrightnessOrVolumeLayout() {
            mBinding.volumeBrightnessLayout.setVisibility(View.GONE);
        }

        @Override
        protected void updateBrightness(float percent) {
            super.updateBrightness(percent);
            mBinding.volumeBrightnessLayout.setVisibility(View.VISIBLE);
            mBinding.volumeBrightnessLayout.setBackgroundResource(R.drawable.icon_video_brightness_bg);
            mBinding.volumeBrightnessPb.setMax(100);
            mBinding.volumeBrightnessPb.setProgress((int) (100 * getNewBrightnessPercent()));
        }

        @Override
        protected void updateVolume(float yDistance) {
            super.updateVolume(yDistance);
            mBinding.volumeBrightnessLayout.setVisibility(View.VISIBLE);
            mBinding.volumeBrightnessLayout.setBackgroundResource(R.drawable.icon_video_volumn_bg);
            mBinding.volumeBrightnessPb.setMax(getMaxVolumeDistance());
            mBinding.volumeBrightnessPb.setProgress((int) getCurrVolumeDistance());
        }

        @Override
        protected void updateVideoProgressUi(int tempNewPosition) {
            super.updateVideoProgressUi(tempNewPosition);
            int duration = (int) getDuration();
            tempNewPosition = tempNewPosition < 0 ? 0 : (tempNewPosition > duration ? duration : tempNewPosition);
            mBinding.durationByUserTxt.setVisibility(View.VISIBLE);
            mBinding.durationByUserTxt.setText(String.format("%s / %s", formatSecond(tempNewPosition / 1000), formatSecond(mBinding.videoView.getDuration() / 1000)));
        }

        @Override
        protected void updateVideoProgress(int newPosition) {
            super.updateVideoProgress(newPosition);
            int duration = (int) getDuration();
            newPosition = newPosition < 0 ? 0 : (newPosition > duration ? duration : newPosition);
            mBinding.durationByUserTxt.setVisibility(View.GONE);
            mBinding.videoView.seekTo(newPosition);
            mProgress.set(newPosition);
        }

        @Override
        protected Rect videoPlayAreaRect() {
            Rect rect = new Rect();
            mBinding.videoViewLayout.getHitRect(rect);
            return rect;
        }

        @Override
        protected void onPlayAreaClick() {
            ILog.ld("[vp]here");
            onTapVideoView();
        }

        @Override
        protected void onPlayAreaDoubleClick() {
            ILog.ld("[vp]here");
            play();
        }
    }

    /**
     * 点击声音开关
     */
    private View.OnClickListener mSoundOpenClick = new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            mBinding.videoView.setPlayerMute(mSoundOpen.get() ? 1 : 0);
            mSoundOpen.set(!mSoundOpen.get());
        }
    };

    /**
     * 点击跳过广告
     */
    private View.OnClickListener mSkipAdClick = new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            ILog.ld("[vp]Click skip ad");
            //mCompletionListener.onCompletion(null);
        }
    };

    /**
     * 点击详情
     */
    private View.OnClickListener mDetailClick = new View.OnClickListener() {

        @Override
        public void onClick(View v) {
        }
    };

    private BroadcastReceiver mNetworkReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (isLocalUrl) return;
            INetworkUtils networkUtils = INetworkUtils.getInstance();
            onNetworkChanged(networkUtils.isWifiConnectedOrConnecting(), networkUtils.isMobileConnectedOrConnectiong());
        }
    };


    /**
     * 如果使用手机流量播放，toast个提示
     */
    private void checkNetWorkAndToast() {
        if (isLocalUrl) return;
        if (!INetworkUtils.getInstance().isWifiConnectedOrConnecting()) {
            Activity activity = mActivityListener.getActivity();
            if (activity instanceof IActivity) {
                ((IActivity) activity).showToast(R.string.video_unwifi_state);
            }
        }
    }

    public long getCurrentPosition() {
        try {
            return mBinding.videoView.getCurrentPosition();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            ILog.le(throwable);
        }
        return 0;
    }

    public long getDuration() {
        try {
            return mBinding.videoView.getDuration();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            ILog.le(throwable);
        }
        return 0;
    }

    public static class VideoPositionCacheManager {

        private static VideoPositionCacheManager sInst;

        private SharedPreferences mPreferences;

        private VideoPositionCacheManager() {
            mPreferences = LBApplication.getInstance().getSharedPreferences("videoplayer.video.position", Context.MODE_PRIVATE);
        }

        public static VideoPositionCacheManager getInstance() {
            if (null == sInst) {
                synchronized (VideoPositionCacheManager.class) {
                    if (null == sInst) {
                        sInst = new VideoPositionCacheManager();
                    }
                }
            }
            return sInst;
        }

        public boolean savePosition(long videoId, long videoPosition) {
            if (videoId == 0) return true;
            ILog.ld("[vp][position]save video %d position %s", videoId, formatSecond(videoPosition / 1000));
            return mPreferences.edit().putLong(videoId + "", videoPosition).commit();
        }

        public long readPosition(long videoId) {
            if (videoId == 0) return 0;
            long videoPosition = mPreferences.getLong(videoId + "", 0);
            ILog.ld("[vp][position]read video %d position %s", videoId, formatSecond(videoPosition / 1000));
            return videoPosition;
        }

        public boolean clearPosition() {
            ILog.lw("[vp][position]in");
            return mPreferences.edit().clear().commit();
        }
    }

    public void setPostVideoMode(boolean bool) {
        mBinding.collectImg.setVisibility(bool ? GONE : (mSimpleMode.get()? View.INVISIBLE: View.VISIBLE));
        mBinding.shareImg.setVisibility(bool ? GONE : (mSimpleMode.get()? View.INVISIBLE: View.VISIBLE));
    }

    private PlayerListener mPlayerListener;
    public void setPlayerListener(PlayerListener listener) {
        this.mPlayerListener = listener;
    }

    public interface PlayerListener{
       void onCompletion(IMediaPlayer mp);
    }
}
